﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Marbles.Core.Connectors;
using System.Data;
using Marbles.Core.Encryption;
using Marbles.Core.Content.Sites;

namespace Marbles.Core.Content.Users
{
    public class User
    {
        public string SiteId { get { return _siteid; } }
        public string UserId { get { return _userid; } }
        public string Username { get { return _username; } set { _username = value; } }
        public string Password { get { return _password; } set { _password = value; } }
        public string Fullname { get { return _fullname; } set { _fullname = value; } }
        public string Email { get { return _email; } set { _email = value; } }
        public bool Enabled { get { return _enabled; } set { _enabled = value; } }
        public DateTime LastLogin { get { return _lastlogin; } }
        public string OpenID { get { return _openid; } set { _openid = value; } }
        public string LastLoginDate { get { return _lastlogin.Year > 1980 ? _lastlogin.ToString("dd/MM/yyyy HH:mm:ss") : ""; } }
        public List<Int32> Groups { get { return _groups; } }

        private List<Int32> _groups = null;
        private string _siteid = string.Empty;
        private string _username = string.Empty;
        private string _password = string.Empty;
        private string _fullname = string.Empty;
        private string _email = string.Empty;
        private bool _enabled = false;
        private DateTime _lastlogin = Marbles.Core.Connectors.DataConnection.MinimumDateTime;
        private string _openid = string.Empty;
        private string _userid = string.Empty;

        public User()
        {
            _groups = new List<Int32>();
            _userid = string.Empty;
            _siteid = string.Empty;
            _username = string.Empty;
            _password = string.Empty;
            _fullname = string.Empty;
            _email = string.Empty;
            _enabled = false;
            _lastlogin = Marbles.Core.Connectors.DataConnection.MinimumDateTime;
            _openid = string.Empty;
        }

        internal void CopyToSite(string siteid)
        {
            _siteid = siteid;
            _userid = Guid.NewGuid().ToString();
        }

        public User(string SiteId, string userid)
            : this()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT * FROM Users WHERE siteid = @siteid AND userid = @userid");
            cmd.AddParameter("@siteid", SiteId);
            cmd.AddParameter("@userid", userid);
            DataTable dt = dbc.FetchDataTable(cmd);

            if (dt.Rows.Count > 0)
            {
                _siteid = SiteId;
                _username = dt.Rows[0]["username"].ToString();
                _password = EncryptionProvider.Decode1(dt.Rows[0]["password"].ToString(), EncryptionProviderType.TripleDES);
                _fullname = dt.Rows[0]["fullname"].ToString();
                _email = dt.Rows[0]["email"].ToString();
                _enabled = Convert.ToBoolean(dt.Rows[0]["enabled"]);
                _lastlogin = Convert.ToDateTime(dt.Rows[0]["lastlogin"]);
                _openid = dt.Rows[0]["openid"].ToString();
                _userid = dt.Rows[0]["userid"].ToString();
                LoadGroups();
            }
        }

        public static User GetRootUser(string siteid)
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT a.userid FROM users a INNER JOIN usergrouplink b ON a.userid = b.userid INNER JOIN usergroups c ON b.groupid = c.groupid AND c.root = 1 WHERE a.siteid = @siteid");
            cmd.AddParameter("@siteid", siteid);
            DataTable dt = dbc.FetchDataTable(cmd);

            if (dt.Rows.Count > 0)
            {
                return new User(siteid, dt.Rows[0]["userid"].ToString());
            }

            return null;
        }

        public static User GetByUsername(string username, string siteid)
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT userid FROM Users WHERE siteid = @siteid AND username = @username");
            cmd.AddParameter("@siteid", siteid);
            cmd.AddParameter("@username", username);
            DataTable dt = dbc.FetchDataTable(cmd);

            if (dt.Rows.Count > 0)
            {
                return new User(siteid, dt.Rows[0]["userid"].ToString());
            }

            return null;
        }

        internal User(DataRow row)
            : this()
        {
            _userid = row["userid"].ToString();
            _siteid = row["siteid"].ToString();
            _username = row["Username"].ToString();
            _password = EncryptionProvider.Decode1(row["password"].ToString(), EncryptionProviderType.TripleDES);
            _fullname = row["fullname"].ToString();
            _email = row["email"].ToString();
            _enabled = Convert.ToBoolean(row["enabled"]);
            _lastlogin = Convert.ToDateTime(row["lastlogin"]);
            _openid = row["openid"].ToString();
            LoadGroups();
        }

        private void LoadGroups()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT groupid FROM usergrouplink u WHERE userid = @userid AND siteid = @siteid;");
            _groups.Clear();
            cmd.AddParameter("@userid", _userid);
            cmd.AddParameter("@siteid", _siteid);

            foreach (DataRow dr in dbc.FetchDataTable(cmd).Rows)
            {
                _groups.Add(Convert.ToInt32(dr["groupid"]));
            }
        }

        private void UpdateGroups()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("DELETE FROM usergrouplink WHERE userid = @userid AND siteid = @siteid");
            cmd.AddParameter("@userid", _userid);
            cmd.AddParameter("@siteid", _siteid);
            dbc.ExecuteCommand(cmd);

            foreach (Int32 group in _groups)
            {
                cmd = new Command("INSERT INTO usergrouplink (userid, siteid, groupid) VALUES (@userid, @siteid, @groupid)");
                cmd.AddParameter("@userid", _userid);
                cmd.AddParameter("@siteid", _siteid);
                cmd.AddParameter("@groupid", group);
                dbc.ExecuteCommand(cmd);
            }
        }

        public void Update()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("UPDATE Users SET username = @username, password = @password, fullname = @fullname, email = @email, enabled = @enabled, openid = @openid WHERE siteid = @siteid AND userid = @userid");
            cmd.AddParameter("@userid", _userid);
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@username", _username);
            cmd.AddParameter("@password", EncryptionProvider.Encode1(_password, EncryptionProviderType.TripleDES));
            cmd.AddParameter("@fullname", _fullname);
            cmd.AddParameter("@email", _email);
            cmd.AddParameter("@enabled", _enabled);
            cmd.AddParameter("@lastlogin", _lastlogin);
            cmd.AddParameter("@openid", _openid);
            dbc.ExecuteCommand(cmd);
            UpdateGroups();
        }

        public void Insert()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("INSERT INTO Users (userid, siteid, username, password, fullname, email, enabled, lastlogin, openid) VALUES (@userid, @siteid, @username, @password, @fullname, @email, @enabled, @lastlogin, @openid)");
            cmd.AddParameter("@userid", _userid);
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@username", _username);
            cmd.AddParameter("@password", EncryptionProvider.Encode1(_password, EncryptionProviderType.TripleDES));
            cmd.AddParameter("@fullname", _fullname);
            cmd.AddParameter("@email", _email);
            cmd.AddParameter("@enabled", _enabled);
            cmd.AddParameter("@lastlogin", _lastlogin);
            cmd.AddParameter("@openid", _openid);
            dbc.ExecuteCommand(cmd);
            UpdateGroups();
        }

        public void Delete()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("DELETE FROM Users WHERE siteid = @siteid AND userid = @userid");
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@userid", _userid);
            dbc.ExecuteCommand(cmd);
            cmd = new Command("DELETE FROM userGroupLink WHERE siteid = @siteid AND userid = @userid");
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@userid", _userid);
            dbc.ExecuteCommand(cmd);
        }

        public static User CreateNew(string SiteId)
        {
            User user = new User();
            user._siteid = SiteId;
            user._userid = Guid.NewGuid().ToString();
            return user;
        }

        public static User GetCurrent()
        {
            if (Authentication.AuthenticationProvider.CreateProviderInstance().CurrentToken == null) { return null; }

            string username = Authentication.AuthenticationProvider.CreateProviderInstance().CurrentToken.Username;
            string siteid = SiteDefinition.GetCurrent().SiteId;
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT * FROM Users WHERE siteid = @siteid AND username = @username");
            cmd.AddParameter("@siteid", siteid);
            cmd.AddParameter("@username", username);
            DataTable dt = dbc.FetchDataTable(cmd);
            if (dt.Rows.Count > 0) { return new User(dt.Rows[0]); }
            return null;
        }
    }
}
